package com.zs.basic.runoob

/**
 *
 * @description
 * @author madison
 * @date 2021/6/1 08:12
 *
 */
fun test() {}

// 函数定义使用关键字 fun，参数格式为：参数 : 类型
fun sum(a: Int, b: Int): Int {
    return a + b
}

// 表达式作为函数体，返回类型自动推断：
fun sum1(a: Int, b: Int) = a + b

// public 方法则必须明确写出返回类型
public fun sum2(a: Int, b: Int): Int = a + b

// 无返回值的函数(类似Java中的void)：
fun printSum(a: Int, b: Int): Unit {
    println(a + b)
}

// 如果是返回 Unit类型，则可以省略(对于public方法也是这样)：
public fun printSum1(a: Int, b: Int) {
    println(a + b)
}

// 函数的变长参数可以用 vararg 关键字进行标识：
fun vars(vararg v: Int) {
    for (vt in v) {
        println(vt)
    }
}

//类型检测及自动类型转换
//我们可以使用 is 运算符检测一个表达式是否某类型的一个实例(类似于Java中的instanceof关键字)。
fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // 做过类型判断以后，obj会被系统自动转换为String类型
        return obj.length
    }
    // 在这里还有一种方法，与Java中instanceof不同，使用!is
//    if (obj !is String) {
//        return null
//    }

    // 这里的obj仍然是Any类型的引用
    return null
}

fun main(args: Array<String>) {
    vars(1, 2, 3, 4, 5)

    // lambda表达式使用实例：
    val sumLambda: (Int, Int) -> Int = { x, y -> x + y }
    println(sumLambda(1, 9))


    // 可变变量定义：var 关键字
    // var <标识符> : <类型> = <初始化值>

    // 不可变变量定义：val 关键字，只能赋值一次的变量(类似Java中final修饰的变量)
    // val <标识符> : <类型> = <初始化值>
    val a: Int = 1
    val b = 1       // 系统自动推断变量类型为Int
    val c: Int      // 如果不在声明时初始化则必须提供变量类型
    c = 1           // 明确赋值

    var m = 5       // 系统自动推断变量类型为Int
    m += 1          // 变量可修改

    // 字符串模板
    // $ 表示一个变量名或者变量值
    // $varName 表示变量值
    // ${varName.fun()} 表示变量的方法返回值:
    val s1 = "a is $a"
    println(s1)
    val s2 = "${s1.replace("is", "was")},but now is $a"
    println(s2)

    // NULL检查机制
    //类型后面加?表示可为空
    var age: String? = "23"
    //抛出空指针异常
    val ages = age!!.toInt()
    //不做处理返回 null
    val ages1 = age?.toInt()
    //age为空返回-1
    val ages2 = age?.toInt() ?: -1
    println(ages2)
    println(parseInt("55555"))

    //以下实例演示如何使用一个返回值可为 null 的函数:
    if (args.size < 2) {
        println("Two integers expected")
        return
    }
    val x = parseInt(args[0])
    val y = parseInt(args[1])
    // 直接使用 `x * y` 会导致错误, 因为它们可能为 null.
    if (x != null && y != null) {
        // 在进行过 null 值检查之后, x 和 y 的类型会被自动转换为非 null 变量
        println(x * y)
    }

    //区间
    for (i in 1..4) print(i) // 输出“1234”
    println()
    for (i in 4..1) print(i) // 什么都不输出
    println("-------------")
    val i = 7
    if (i in 1..10) {
        println(i)
    }
    // 使用 step 指定步长
    for (i in 1..4 step 2) print("$i\t") // 输出“13”
    println()
    for (i in 4 downTo 1 step 2) print("$i\t") // 输出“42”
    println()
    // 使用 until 函数排除结束元素
    for (i in 1 until 10) {
        print("$i\t")
    }
    println()

    println(a === a)
    //经过了装箱，创建了两个不同的对象
    val boxedA: Int? = a
    val antherBoxedA: Int? = a
    //虽然经过了装箱，但是值是相等的
    println(boxedA === antherBoxedA)//  false，值相等，对象地址不一样
    println(boxedA == antherBoxedA)// true，值相等


    val h: Byte = 1 // OK, 字面值是静态检测的
//    val j: Int = h // 错误

    val array = arrayOf(1, 2, 3)
    println(array.size)
    println(array.forEach { i -> print("$i\t") })
    val array1 = Array(3) { i -> (i * 2) }
    println(array1.forEach { i -> print("$i\t") })
    println()

    var text = """
    多行字符串
    多行字符串
    """.trimMargin()
    println(text)   // 输出有一些前置空格

    //默认 | 用作边界前缀，但你可以选择其他字符并作为参数传入，比如 trimMargin(">")。
    text = """
    |多行字符串
    |菜鸟教程
    |多行字符串
    |Runoob
    """.trimMargin()
    println(text)    // 前置空格删除了


    val price = """
    ${'$'}9.99
    $$i
    """
    println(price)  // 求值结果为 $9.99
}

//当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。
//当 str 中的字符串内容不是一个整数时, 返回 null:
fun parseInt(str: String): Int? {
    return str.toInt()
}